package io.sundial.discovery.impl;

import io.sundial.core.context.Context;
import io.sundial.core.lifecycle.exception.InitializingException;
import io.sundial.discovery.Discoverer;
import io.sundial.discovery.exception.DiscoveringException;
import io.sundial.job.Job;
import io.sundial.job.JobKey;
import io.sundial.util.ConcurrentLRUHashMap;

import java.util.concurrent.ConcurrentMap;

/**
 * LRU缓存的作业发现者
 *
 * @author Payne 646742615@qq.com
 * 2018/12/26 20:38
 */
public abstract class LRUCachingDiscoverer extends EventSupportingDiscoverer implements Discoverer {
    private ConcurrentMap<JobKey, Job> jobCache;
    private int segmentCapacity = 24;
    private float loadFactor = 0.75f;
    private int concurrencyLevel = 16;

    @Override
    protected void initializing(Context context) throws InitializingException {
        super.initializing(context);

        jobCache = new ConcurrentLRUHashMap<>(segmentCapacity, loadFactor, concurrencyLevel);
    }

    @Override
    public Job discover(String jobName, String jobGroup) throws DiscoveringException {
        Job job = jobCache.get(new JobKey(jobName, jobGroup));
        if (job == null) {
            job = find(jobName, jobGroup);
            if (job == null) {
                throw new DiscoveringException("jobGroup: " + jobGroup + ", jobName: " + jobName);
            }
            save(job);
        }
        return job;
    }

    protected abstract Job find(String jobName, String jobGroup);

    protected void save(Job job) {
        JobKey jobKey = new JobKey(job.name(), job.group());
        jobCache.put(jobKey, job);
    }

    public int getSegmentCapacity() {
        return segmentCapacity;
    }

    public void setSegmentCapacity(int segmentCapacity) {
        this.segmentCapacity = segmentCapacity;
    }

    public float getLoadFactor() {
        return loadFactor;
    }

    public void setLoadFactor(float loadFactor) {
        this.loadFactor = loadFactor;
    }

    public int getConcurrencyLevel() {
        return concurrencyLevel;
    }

    public void setConcurrencyLevel(int concurrencyLevel) {
        this.concurrencyLevel = concurrencyLevel;
    }
}
